use std::{env, error::Error, fs};
pub struct Config {
    pub query:String,
    pub filename:String,
    pub case_sensitive:bool,
}

impl Config {
    // 注意要是可变的
    pub fn new(mut args: env::Args) -> Result<Config, &'static str> {
        // if args.len() < 3 {
        //     return Err("参数数量不足")
        // }
        // 首个参数是可执行文件名，所以忽略它
        args.next();
        // 注释掉之前的做法, clone毕竟是消耗性能的
        // let query = args[1].clone();
        // let filename = args[2].clone();
        let query = match args.next() {
            Some(args) => args,
            None => return Err("没有提供查询字符串")
        };
        let filename = match args.next() {
            Some(args) => args,
            None => return Err("没有提供文件名")
        };
        let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
        Ok(Config {query, filename, case_sensitive})
    }
}

pub fn run(config: Config) -> Result<(), Box<dyn Error>>{
    let bools = config.case_sensitive;
    let contents = fs::read_to_string(config.filename)?;
    if bools {
        search(&config.query, &contents)
    } else {
        search_insensitive(&config.query, &contents)
    }; 
    Ok(())
}


pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    // let mut result:Vec<&str> = Vec::new();
    // 注释掉之前的
    // for line in contents.lines() {
    //     if line.contains(query) {
    //         result.push(line)
    //     }
    // }
    // 充分利用contents.lines()的迭代器方法filter
    let result = contents.lines().filter(|line| line.contains(query)).collect();
    println!("结果1是: {:?}", result);
    result
}

// 大小写不敏感
pub fn search_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    // 这个query拥有了所有权
    // let query = query.to_lowercase();
    // let mut result = Vec::new();
    // for line in contents.lines() {
    //     if line.to_lowercase().contains(&query) {
    //         result.push(line);
    //     }
    // }
    let result = contents.lines().filter(|line| line.to_lowercase().contains(&query.to_lowercase())).collect();
    println!("结果2是: {:?}", result);
    result
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_search() {
        let contents = "Rust: safe, concurrent, practical, and fun.";
        assert_eq!(search("Rust",contents), vec!["Rust: safe, concurrent, practical, and fun."]);
    }

    #[test]
    fn search_insensitive_test() {
        let contents = "Rust: safe,
        \n concurrent, practical, and fun.
        \nrust is fine
        ";
        assert_eq!(search_insensitive("rust",contents), vec!["Rust: safe,", "rust is fine"]);
    } 
}
